using Nop.Core;
using Nop.Core.ApiDataModel;
using Nop.Core.Domain.Customers;
using Nop.Services.Authentication;
using Nop.Services.Common;
using Nop.Services.Customers;
using Nop.Services.Localization;
using Nop.Services.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using Nop.Core.Log;
using Spotshub.Api.Filter;
using System.Net.Http;
using System.IO;
using System.Text;
using Nop.Core.Domain.Common;
using Nop.Services.Logistics;
using Spotshub.Api.Models;

namespace Spotshub.Api.Controllers.V1
{
    [ExceptionHandlerAttribute]
    public class AddressController : ApiController
    {
        private readonly IWorkContext _workContext;
        private readonly ICustomerService _customerService;
        private readonly ICustomerRegistrationService _customerRegistrationService;
        private readonly IAuthenticationService _authenticationService;
        private readonly ICustomerActivityService _customerActivityService;
        private readonly ILocalizationService _localizationService;
        private readonly IAddressService _addressService;
        private readonly ILogisticsService _logisticsService;
        private ILog _logService;
        public AddressController(
            IWorkContext workContext,
            ICustomerService customerService,
            ICustomerRegistrationService customerRegistrationService,
            IAuthenticationService authenticationService,
            ICustomerActivityService customerActivityService,
            IAddressService addressService,
            ILocalizationService localizationService,
            ILogisticsService logisticsService)
        {
            this._workContext = workContext;
            this._customerService = customerService;
            this._customerRegistrationService = customerRegistrationService;
            this._authenticationService = authenticationService;
            this._customerActivityService = customerActivityService;
            this._localizationService = localizationService;
            this._addressService = addressService;
            this._logService = LogManager.GetInstance().GetILog();
            this._logisticsService = logisticsService;
        }


        // Get api/Address/GetAddress
        public ListResult<Nop.Core.ApiDataModel.Address> Get()
        {
            //ILog logService = LogManager.GetInstance().GetILog();

            CheckCustomerLogin();
            var addresses = new ListResult<Nop.Core.ApiDataModel.Address>();

            var aaa = _workContext.CurrentCustomer.Addresses;
            _workContext.CurrentCustomer.Addresses.ToList().ForEach(address =>
                addresses.Items.Add(new Nop.Core.ApiDataModel.Address(address))
                );

            if (addresses.Items != null && addresses.Items.Any())
                addresses.Items = addresses.Items.OrderByDescending(addr => addr.Id).ToList();
            addresses.Success = true;
            return addresses;
        }

        // Get api/Address/Get/2
        public ListResult<Nop.Core.ApiDataModel.Address> Get(int id)
        {
            CheckCustomerLogin();
            var address = _workContext.CurrentCustomer.Addresses.ToList().FirstOrDefault(addr => addr.Id == id);
            if (address != null)
            {
                return new ListResult<Nop.Core.ApiDataModel.Address>(new Nop.Core.ApiDataModel.Address(address)) { Success = true };
            }
            else
            {
                return new ListResult<Nop.Core.ApiDataModel.Address>() { Success = false, Message = "No addresses" };
            }
        }

        // POST api/Address/Add
        [HttpPost]
        public object Add([FromBody]Nop.Core.ApiDataModel.Address newAddress, bool IsBillingAddress = false, bool IsShippingAddress = false)
        {
            CheckCustomerLogin();


            var addressModel = new AddressModel
            {
                FirstName = newAddress.FirstName,
                LastName = newAddress.LastName,
                Email = newAddress.Email,
                Company = newAddress.Company,
                CountryId = newAddress.CountryId,
                StateProvinceId = newAddress.StateProvinceId,
                City = newAddress.City,
                Address1 = newAddress.Address1,
                Address2 = newAddress.Address2,
                ZipPostalCode = newAddress.ZipPostalCode,
                CellPhoneNumber = newAddress.CellPhoneNumber,
                PhoneNumber = newAddress.PhoneNumber,
                FaxNumber = newAddress.FaxNumber
            };
            var errList = new List<string>();
            var res = new Spotshub.Api.Validators.AddressValidator(_localizationService, _logisticsService).Validate(addressModel);
            if (!res.IsValid)
            {
                errList.AddRange(res.Errors.Select(error => error.ErrorMessage));
            }
             

            var address = _workContext.CurrentCustomer.Addresses == null ? null :
                _workContext.CurrentCustomer.Addresses.ToList().FindAddress(
                newAddress.FirstName, newAddress.LastName,
                newAddress.PhoneNumber, newAddress.CellPhoneNumber,
                newAddress.Email, newAddress.FaxNumber, newAddress.Company,
                newAddress.Address1, newAddress.Address2, newAddress.City,
                newAddress.StateProvinceId, newAddress.ZipPostalCode, newAddress.CountryId
                );
            if (address == null && errList.Count == 0)
            {
                //address is not found. let's create a new one
                address = newAddress.ToEntity();
                address.CreatedOnUtc = DateTime.UtcNow;
                //some validation
                if (address.CountryId == 0)
                    address.CountryId = null;
                if (address.StateProvinceId == 0)
                    address.StateProvinceId = null;
                //var addressList = new List<Nop.Core.Domain.Common.Address>();
                //if (_workContext.CurrentCustomer.Addresses != null)
                //    addressList.AddRange(_workContext.CurrentCustomer.Addresses);
                //addressList.Add(address);
                //_workContext.CurrentCustomer.Addresses = addressList;

                //_customerService.UpdateCustomer(_workContext.CurrentCustomer);
                //_addressService.InsertAddress(address);
                var strsql = new StringBuilder();
                strsql.Append("DECLARE @inserId int" + "\n");
                strsql.Append("set @inserId=0" + "\n");
                strsql.Append("begin " + "\n");
                strsql.Append(
                    "   Insert into [Address](FirstName,LastName,Email,Company,CountryId,StateProvinceId,City,Address1,Address2,ZipPostalCode,PhoneNumber,CellPhoneNumber,FaxNumber,TypeId,CreatedOnUtc)" +
                    "\n");
                strsql.Append("  values('" + address.FirstName + "','" + address.LastName + "','" + address.Email +
                              "','" + address.Company + "','" + address.CountryId + "','" + address.StateProvinceId +
                              "',");
                strsql.Append("'" + address.City + "','" + address.Address1 + "','" + address.Address2 + "','" +
                              address.ZipPostalCode + "','" + address.PhoneNumber + "','" + address.CellPhoneNumber +
                              "','" + address.FaxNumber + "','" + address.TypeId + "','" + address.CreatedOnUtc + "')" +
                              "\n");
                strsql.Append("  select @inserId=SCOPE_IDENTITY()" + "\n");
                strsql.Append("if @inserId>0" + "\n");
                strsql.Append("   begin" + "\n");
                strsql.Append("     insert into [CustomerAddresses](Customer_Id,Address_Id)" + "\n");
                strsql.Append("     values('" + _workContext.CurrentCustomer.Id + "',@inserId)" + "\n");
                strsql.Append("end" + "\n");
                strsql.Append("end" + "\n");

                if (IsBillingAddress && IsShippingAddress)
                {
                    strsql.Append(
                        " update Customer set BillingAddress_Id=@inserId,ShippingAddress_Id=@inserId where Id= " +
                        _workContext.CurrentCustomer.Id);
                }
                else if (IsBillingAddress)
                {
                    strsql.Append(
                        " update Customer set BillingAddress_Id=@inserId where Id= " +
                        _workContext.CurrentCustomer.Id);
                }
                else if (IsShippingAddress)
                {
                    strsql.Append(
                        " update Customer set ShippingAddress_Id=@inserId where Id= " +
                        _workContext.CurrentCustomer.Id);
                }


                var insertsql = _customerService.ExcuteSql(strsql.ToString(), _workContext.CurrentCustomer);
                if (insertsql)
                {
                    return new {success = true};
                }
                errList.Add("Failed to add address.");
            }
            if (address!=null)
            {
                errList.Add("Don't add duplicate address.");
            }
            return new { success = false, errorMessage = errList.FirstOrDefault() };
        }

        // POST api/Checkout/SaveAddress
        [HttpPost]
        public bool Edit([FromBody]Nop.Core.ApiDataModel.Address newAddress)
        {
            CheckCustomerLogin();

            if (newAddress.Id != null && newAddress.Id > 0)
            {
                if (_workContext.CurrentCustomer.Addresses.ToList().FirstOrDefault(addr => addr.Id == newAddress.Id) == null)
                {
                    // could not find address with matching addressId
                    return false;
                }
                else
                {
                    // updating existing address
                    var address = _workContext.CurrentCustomer.Addresses.ToList().FirstOrDefault(addr => addr.Id == newAddress.Id);
                    newAddress.UpdateEntity(address);
                    address.Id = newAddress.Id.Value;
                    address.CreatedOnUtc = DateTime.UtcNow;
                    //some validation
                    if (address.CountryId == 0)
                        address.CountryId = null;
                    if (address.StateProvinceId == 0)
                        address.StateProvinceId = null;
                    //_customerService.UpdateCustomer(_workContext.CurrentCustomer);
                    //_addressService.UpdateAddress(address);

                    var updateStrsql = "update Address set FirstName='" + address.FirstName + "'" +
                                       ",LastName='" + address.LastName + "'" +
                                       ",Email='" + address.Email + "'" +
                                       ",Company='" + address.Company + "'" +
                                       ",CountryId='" + address.CountryId + "' " +
                                       ",StateProvinceId='" + address.StateProvinceId + "'" +
                                       ",City='" + address.City + "'" +
                                       ",Address1='" + address.Address1 + "'" +
                                       ",Address2='" + address.Address2 + "'" +
                                       ",ZipPostalCode='" + address.ZipPostalCode + "'" +
                                       ",PhoneNumber='" + address.PhoneNumber + "'" +
                                       ",CellPhoneNumber='" + address.CellPhoneNumber + "'  " +
                                       ",FaxNumber='" + address.FaxNumber + "' " +
                                       ",CreatedOnUtc='" + address.CreatedOnUtc + "' where Id=" + address.Id;
                    var bsql = _customerService.ExcuteSql(updateStrsql, _workContext.CurrentCustomer);
                    if (bsql)
                    {
                        return true;
                    }
                    return false;
                }
            }
            return false;
        }

        // Get api/Checkout/GetAddress
        [HttpPost]
        public bool Delete(int Id)
        {
            try
            {
                if (_workContext.CurrentCustomer.IsGuest())
                {
                    _logService.Debug("Anonymous checkout is not allowed");
                    return false;
                }

                var address = _workContext.CurrentCustomer.Addresses.ToList().FirstOrDefault(addr => addr.Id == Id);

                if (address == null)
                {
                    // could not find address with matching addressId
                    _logService.Debug("Address is null");
                    return false;
                }

                // updating existing address
                //var list = _workContext.CurrentCustomer.Addresses.ToList();
                //list.Remove(address);
                //_workContext.CurrentCustomer.Addresses = list;
                //_customerService.UpdateCustomer(_workContext.CurrentCustomer);
                ////var sqlstr = "delete [dbo].[CustomerAddresses] where Address_Id=" + Id;

                var sqlstr = "begin " + "\n";
                sqlstr += "DECLARE  @CustomerId int,@AddressId int" + "\n";
                sqlstr += "set @CustomerId=" + _workContext.CurrentCustomer.Id + "\n";
                sqlstr += "set @AddressId=" + Id + "\n";
                sqlstr += "if exists(select Id from Customer where BillingAddress_Id=@AddressId or ShippingAddress_Id=@AddressId  and Id=@CustomerId)" + "\n";
                sqlstr += "begin" + "\n";
                sqlstr += "if exists(select Id from Customer where BillingAddress_Id=@AddressId)" + "\n";
                sqlstr += "begin" + "\n";
                sqlstr += "update Customer set BillingAddress_Id=NUll where Id=@CustomerId" + "\n";
                sqlstr += "end" + "\n";
                sqlstr += "if exists(select Id from Customer where ShippingAddress_Id=@AddressId)" + "\n";
                sqlstr += "begin" + "\n";
                sqlstr += "update Customer set ShippingAddress_Id=NUll where Id=@CustomerId" + "\n";
                sqlstr += "end" + "\n";
                sqlstr += "end" + "\n";
                sqlstr += "delete [CustomerAddresses] where Customer_Id=@CustomerId and Address_Id=@AddressId" + "\n";
                sqlstr += "end" + "\n";
                var bSql = _customerService.ExcuteSql(sqlstr, _workContext.CurrentCustomer);
                if (bSql)
                {
                    return true;
                }
                return false;

            }
            catch (Exception ex)
            {
                _logService.Exception(ex);
                return false;
            }

        }

        private void CheckCustomerLogin()
        {
            if (_workContext.CurrentCustomer.IsGuest())
                throw new Exception("Anonymous checkout is not allowed");
        }
    }
}
